package logicGame;

import logicGame.Cards.*;
import java.awt.Color;
import java.io.File;
import java.io.*;
import logicGame.States.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import java.util.Scanner;
import javax.swing.JTextField;

public class Game implements Serializable {

    State e;
    ArrayList<Player> p;
    ArrayList<Card> deck;
    ArrayList<Card> boardDeck;
    ArrayList<Color> colors;
    Board b;
    Player active;
    int nPlayers, place;
    boolean changed;

    public Game() {
        e = new Setup(this);
        deck = new ArrayList<>();
        boardDeck = new ArrayList<>();
        colors = new ArrayList<>();
        colors.add(Color.RED);
        colors.add(Color.BLUE);
        colors.add(Color.YELLOW);
        colors.add(Color.GREEN);
        colors.add(Color.ORANGE);
        place = -1;
    }

    public State getState() {
        return e;
    }

    public void setState(State e) {
        this.e = e;
    }

    public Board getBoard() {
        return b;
    }

    public Player getActivePlayer() {
        return active;
    }

    public void setActivePlayer(Player active) {
        this.active = active;
    }

    public void resetChanged() {
        changed = false;
    }

    public void setChanged(boolean x) {
        changed = x;
    }

    public boolean getChanged() {
        return changed;
    }

    //Parte dos estados---------------------------------------------------------
    public void config(int nPlayers, ArrayList<JTextField> pNames) {
        setState(getState().config(nPlayers, pNames));
    }

    public void bet(int coins) {
        setState(getState().bet(coins, active));
    }

    public void buyCard(int n) {
        setState(getState().buy(n));
    }

    public void proxPlayer() {
        setState(getState().proxPlayer());
    }

    public void doAction(int i) {
        try {
            if (checkAction(place, i)) {
                setState(getState().choice(active, b, i));
            } else {
                place = i;
            }
        } catch (Exception e) {
            //ainda nao tem ultima carta
        }
    }

    public void chooseAction(int op) {
        setState(getState().pick(op));
    }

    public void chooseArmy(Player p) {
        setState(getState().chooseArmy(p, b, place));
    }

    //fim dos estados-----------------------------------------------------------
    public String endGame() {
        String str;
        int aux, biggest = 0;
        Player temp;
        ArrayList<Player> winners = new ArrayList<>();

        //calcula pontos
        for (int i = 0; i < p.size(); i++) {
            p.get(i).countResources();
        }
        b.countPlace(p);
        b.countContinentPoints(p);

        //conta Pontos Victoria, escolhe melhores 
        for (int i = 0; i < p.size(); i++) {
            aux = p.get(i).getVictoryPoints();
            temp = p.get(i);
            if (aux > biggest) {
                biggest = aux;
                winners.clear();
                winners.add(temp);
            } else if (!winners.isEmpty() && aux == winners.get(0).getVictoryPoints()) {
                winners.add(temp);
            }
        }

        //Caso empate 1, conta moedas
        if (winners.size() > 1) {
            biggest = 0;
            for (int i = 0; i < winners.size(); i++) {
                temp = winners.get(i);
                aux = winners.get(i).getCoin();
                if (aux > biggest) {
                    biggest = aux;
                    winners.clear();
                    winners.add(temp);
                } else if (aux == biggest) {
                    winners.add(temp);
                }
            }
        }

        //Caso empate 2, Conta exercitos
        if (winners.size() > 1) {
            biggest = 0;
            for (int i = 0; i < winners.size(); i++) {
                temp = winners.get(i);
                aux = b.countTroops(temp);
                if (aux > biggest) {
                    biggest = aux;
                    winners.clear();
                    winners.add(temp);
                } else if (aux == biggest) {
                    winners.add(temp);
                }
            }
        }

//        Caso empate 3, Conta controlo regioes
        if (winners.size() > 1) {
            biggest = 0;
            for (int i = 0; i < winners.size(); i++) {
                temp = winners.get(i);
                aux = temp.getTotalEmpiresOwned();
                if (aux > biggest) {
                    biggest = aux;
                    winners.clear();
                    winners.add(temp);
                } else if (aux == biggest) {
                    winners.add(temp);
                }
            }
        }
        
        if (winners.size() > 1) {
            return str = "Empate!";
        } else {
            winners.get(0).setWinner(true);
            return str = winners.get(0).getName() + " Ganhou!";
        }
    }

    public ArrayList<Card> getAllBoardDeck() {
        return boardDeck;
    }

    public int getPlace() {
        return place;
    }

    public void setPlace(int place) {
        this.place = place;
    }

    public boolean checkAction(int i, int f) {
        Card c = active.getLastCard();

        if (c.getAction() instanceof Delete) {
            return b.checkArmy(f);

        } else if (c.getAction() instanceof Found && active.getNEmpires() > 0) {
            return b.checkArmyPresence(active, f);

        } else if (c.getAction() instanceof Move) {

            if (i != -1) {
                if (c.isEarth() && b.checkMovementEarth(active, i, f)) {
                    return true;
                } else {
                    return (c.isWater() && b.checkMovementWater(active, i, f));
                }
            } else {
                return false;
            }
        } else if (c.getAction() instanceof Place && active.getNTroops() > 0) {
            if (f == 0) {
                return true;
            } else {
                return b.checkPlace(active, f);
            }

        } else {
            return false;
        }
    }

    public int getnPlayers() {
        return nPlayers;
    }

    public void setnPlayers(int nP) {
        this.nPlayers = nP;
        p = new ArrayList<>();
        b = new Board();
    }

    public Player getPlayer(int index) {
        return p.get(index);
    }

    public ArrayList<Player> getPlayers() {
        return p;
    }

    public void changePlayerName(int index, String name) {
        getPlayer(index).setName(name);
    }

    public void addPlayer(String name, int coins, boolean ia) {

        p.add(new Player(name, coins, colors.get(p.size()), ia));
    }

    public void nextPlayer() {
        int x = p.indexOf(getActivePlayer());
        if (p.size() - 1 == x) {
            setActivePlayer(p.get(0));
            return;
        }
        setActivePlayer(p.get(x + 1));
    }

    public void inicializeDeck() {
        File file1;
        Scanner input = null;
        int code, nResources, flagPlayers, earth, earth1 = 0, water, water1 = 0, quant, quant1 = 0, counter = 1;
        String resource, descr;
        try {
            file1 = new File("src/dataStruct.txt");
            input = new Scanner(file1);
            while (input.hasNextLine() != false) {

                code = input.nextInt();
                resource = input.next();
                nResources = input.nextInt();
                flagPlayers = input.nextInt();
                earth = input.nextInt();
                water = input.nextInt();
                quant = input.nextInt();

                if (code == 4 || code == 5 || code == 6 || code == 7) {
                    earth1 = input.nextInt();
                    water1 = input.nextInt();
                    quant1 = input.nextInt();
                }
                descr = input.nextLine();

                if (flagPlayers == 1 && nPlayers != 5) {
                    //so entra aqui quando nao e preciso criar as cartas para quando ha 5 jogadores
                } else if (code == 0 || code == 1 || code == 2) {
                    deck.add(new Card(code, earth, water, descr, resource, nResources, quant, counter));
                } else if (code == 5) {
                    deck.add(new AndCard(code, earth, water, descr, resource, nResources, quant, quant1, earth1, water1, counter));
                } else if (code == 4 || code == 6 || code == 7) {
                    deck.add(new OrCard(code, earth, water, descr, resource, nResources, quant, quant1, earth1, water1, counter));
                }
                counter++;
            }

        } catch (FileNotFoundException s) {
            System.out.println("Ficheiro não existente : ");
        }
    }

    public void initializeBoardDeck() {
        if (boardDeck.isEmpty()) {
            for (int i = 0; i < 6; i++) {
                Random randomGenerator = new Random();
                int rand = randomGenerator.nextInt(deck.size());
                boardDeck.add(deck.get(rand));
                deck.remove(rand);
            }
        } else if (!deck.isEmpty()) {
            Random randomGenerator = new Random();
            int rand = randomGenerator.nextInt(deck.size());
            boardDeck.add(deck.get(rand));
            deck.remove(rand);
        }
    }

    public StringBuilder getBoardDeck() {
        StringBuilder descr = new StringBuilder();
        for (int i = 0; i < boardDeck.size(); i++) {
            if (i == 0) {
                descr.append("\n\n").append("Carta nº").append(i + 1).append("  Preço: 0").append("\t").append(boardDeck.get(i).toString()).append("\n");
            } else if (i == 1 || i == 2) {
                descr.append("\n").append("Carta nº").append(i + 1).append("  Preço: 1").append("\t").append(boardDeck.get(i).toString()).append("\n");
            } else if (i == 3 || i == 4) {
                descr.append("\n").append("Carta nº").append(i + 1).append("  Preço: 2").append("\t").append(boardDeck.get(i).toString()).append("\n");
            } else {
                descr.append("\n").append("Carta nº").append(i + 1).append("  Preço: 3").append("\t").append(boardDeck.get(i).toString()).append("\n\n");
            }
        }
        return descr;
    }

    public void saveGame(String filename) {

        try {
            FileOutputStream fileOut = new FileOutputStream(filename + ".save");
            ObjectOutputStream out = new ObjectOutputStream(fileOut);
            out.writeObject(this);
            out.close();
            fileOut.close();
        } catch (IOException i) {
            i.printStackTrace();
        }
    }

    public boolean gameFinish() {
        int aux = 0, num = 0;

        if (p.size() == 2) {
            num = 13;
        } else if (p.size() == 3) {
            num = 10;
        } else if (p.size() == 4) {
            num = 8;
        } else if (p.size() == 5) {
            num = 7;
        }

        for (int i = 0; i < p.size(); i++) {
            if (p.get(i).getHand().size() == num) {
                aux++;
            }
        }

        return aux == p.size();
    }

    public StringBuilder scoreToString() {
        StringBuilder str = new StringBuilder();
        str.append("Pontuação Final:\n  ");
        for (int i = 0; i < p.size(); i++) {
            str.append("   "+p.get(i).getName()).append("\t   Pontos:  ").append(p.get(i).getVictoryPoints()).append("\n    ");
        }
        return str;
    }

    public ArrayList<Player> getPPlace() {
        
        return b.getPPlace(p, place);
    }

    public HashMap troopToColor() {
        return b.troopToColor();
    }
}
